<!--
  文件描述：二次封装级联选择器
  创建时间：2023/9/12 13:48
  创建人：二
-->
<template>
  <div class="m-select-tree">
    <el-select
      ref="selectTree"
      v-model="selectValue"
      :multiple="multiple"
      :placeholder="placeholder"
      :clearable="clearable"
      @remove-tag="removeTag"
      @clear="handleClear"
    >
      <el-option
        v-for="item in optionData(treeData)"
        :label="item.label"
        :value="item.value"
        :key="item.value"
        style="display: none;"/>
      <el-tree
        ref="tree"
        :data="treeData"
        :props="treeProps"
        :node-key="nodeKey"
        highlight-current
        :expand-on-click-node="false"
        :check-on-click-node="true"
        :show-checkbox="multiple"
        @current-change="currentChange"
        @check="check"
      />
    </el-select>
  </div>
</template>

<script>
export default {
  name: 'MSelectTree',
  model: {
    prop: 'value',
    event: 'updateValue'
  },
  props: {
    value: {
      required: true
    },
    // 提示语句
    placeholder: {
      type: String,
      default: '请选择'
    },
    // 主键
    nodeKey: {
      type: String,
      default: 'id'
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 多选
    multiple: {
      type: Boolean,
      default: false
    },
    // 清除
    clearable: {
      type: Boolean,
      default: true
    },
    // 下拉数据
    treeData: {
      type: Array,
      default() {
        return []
      }
    },
    // 树形props
    treeProps: {
      default() {
        return {
          children: 'children',
          label: 'label',
          disabled: 'disabled'
        };
      }
    }
  },
  watch: {
    value: {
      handler() {
        this.$nextTick(() => {
          this.setCheckedKeys()
        })
      },
      deep: true,
      immediate: true
    }
  },
  data() {
    return {
      selectValue: null
    }
  },

  methods: {
    // 树形转平面的迭代方法
    optionData(array, result=[], pLabel = '') {
      const { nodeKey, multiple, treeProps: { children, label } } = this;
      array.forEach(item => {
        item.pLabel = pLabel ? pLabel + ' / ' + item[label] : item[label];
        if(!multiple) {
          result.push({
            label: item[label],
            value: item[nodeKey]
          })
        }
        if (item[children] && item[children].length !== 0) {

          this.optionData(item.children, result, item.pLabel)
        }else if(multiple){
          result.push({
            label: item.pLabel,
            value: item[nodeKey]
          })
        }
      })
      return JSON.parse(JSON.stringify(result))
    },
    // 当前选中节点变化时触发的事件
    currentChange(data) {
      const { multiple, nodeKey } = this;
      if(multiple) return;
      this.selectValue = data[nodeKey];
      this.$emit('updateValue', data[nodeKey]);
      this.$emit('change', {
        value: data[nodeKey],
        data
      })
      this.$refs.selectTree.blur();
    },
    // 当复选框被点击的时候触发
    check(data, { checkedNodes }) {
      const { multiple, nodeKey, treeProps: { children } } = this;
      if(!multiple) return;
      let value = [], selectData = [];
      checkedNodes.forEach(item => {
        if(!item[children]) {
          value.push(item[nodeKey]);
          selectData.push(item);
        }
      })
      this.selectValue = value;
      this.$emit('updateValue', value);
      this.$emit('change', {
        value: value,
        data: selectData
      })
    },
    // 设置选中
    setCheckedKeys() {
      const { multiple, value, selectValue, treeProps: { label } } = this;
      const tree = this.$refs.tree;
      if(JSON.stringify(value) === JSON.stringify(selectValue)) return;
      this.selectValue = value;
      if(tree) {
        if(multiple) {
          tree.setCheckedKeys(Array.isArray(value) ? value : []);
        } else {
          tree.setCurrentKey(value);
        }
      }
    },
    // 多选模式下移除tag时触发
    removeTag() {
      this.$refs.tree.setCheckedKeys(this.selectValue)
    },
    // 点击清空按钮时触发
    handleClear() {
      const { multiple } = this;
      this.selectValue = null;
      const tree = this.$refs.tree;
      if(multiple) {
        tree.setCheckedKeys([]);
        this.$emit('updateValue', []);
        this.$emit('change', {
          value: [],
          data: []
        })
      }else {
        tree.setCurrentKey('');
        this.$emit('updateValue', '');
        this.$emit('change', {
          value: '',
          data: null
        })
      }

    }
  }
}
</script>

<style scoped lang="scss">

</style>
